/**
 * @file WeakPtr.l
 */
#ifndef INCLUDED_NTENGINE_SHAREDPTRIMPL_H
#define INCLUDED_NTENGINE_SHAREDPTRIMPL_H

#include "NTEngine/NTEngine.h"
#include "NTEngine/Base/SharedPtr.h"


namespace NTEngine {

template < typename T > struct SharedPtrTraits {
    typedef T& Reference;
	typedef T& ConstReference;
};

template<> struct SharedPtrTraits< void > {
    typedef void Reference;
	typedef void ConstReference;
};

template< typename T > void SingleDeleter( T* p ) {
	delete p;
}

template< typename T > void ArraySpDeleter( T* p ) {
	delete[] p;
}

template< class T > SharedPtr< T >::SharedPtr()
: m_Ptr( 0 )
, m_Count() {
}

template< class T > template< class U> SharedPtr< T >::SharedPtr( U* ptr )
: m_Ptr( static_cast< T* >( ptr ) )
, m_Count( ptr, SingleDeleter< U > ) {
}

template< class T > template< class U, class DeleterU > SharedPtr< T >::SharedPtr( U* ptr, DeleterU del )
: m_Ptr( static_cast< T* >( ptr ) )
, m_Count( ptr, del ) {
}

template< class T > template< class U > SharedPtr< T >::SharedPtr( const SharedPtr< U >& a )
: m_Ptr( static_cast< T* >( a.m_Ptr ) )
, m_Count( a.m_Count ) {
}

template< class T > typename SharedPtr< T >::Reference SharedPtr< T >::operator*() {
	ASSERT( m_Ptr && "null ptr object." );
	return *m_Ptr;
}

template< class T > typename SharedPtr< T >::ConstReference SharedPtr< T >::operator*() const {
	ASSERT( m_Ptr && "null ptr object." );
	return *m_Ptr;
}

template< class T > T* SharedPtr< T >::operator->() {
	ASSERT( m_Ptr && "null ptr object." );
	return m_Ptr;
}

template< class T > const T* SharedPtr< T >::operator->() const {
	ASSERT( m_Ptr && "null ptr object." );
	return m_Ptr;
}

template< class T > typename SharedPtr< T >::Reference SharedPtr< T >::operator[]( int i ) {
	ASSERT( m_Ptr && "null ptr object." );
	return m_Ptr[ i ];
}

template< class T > typename SharedPtr< T >::ConstReference SharedPtr< T >::operator[]( int i ) const {
	ASSERT( m_Ptr && "null ptr object." );
	return m_Ptr[ i ];
}

template< class T > bool SharedPtr< T >::operator==( const SharedPtr< T >& a ) const {
	return m_Ptr == a.m_Ptr;
}

template< class T > bool SharedPtr< T >::operator!=( const SharedPtr< T >& a ) const {
	return m_Ptr != a.m_Ptr;
}

template< class T > bool SharedPtr< T >::operator<( const SharedPtr< T >& a ) const {
	return m_Ptr < a.m_Ptr;
}

template< class T > SharedPtr< T >::operator void*() const {
	return ( m_Ptr ) ? reinterpret_cast< void* >( ~0 ) : 0;
}

// 
template< class T > SharedPtr< T > SharedPtrCreator::create( T* p ) {
	return SharedPtr< T >( p );
}

template< class T > SharedPtr< T > SharedPtrCreator::createArray( T* p ) {
	return SharedPtr< T >( p, ArraySpDeleter< T > );
}

// 
class SharedPtrCountedBase {
public:
	SharedPtrCountedBase() : m_Count( 1 ) {
	}
	virtual ~SharedPtrCountedBase() {
	}
	void refer(){
		++m_Count;
	}
	int unref() {
        return --m_Count;
	}
	int m_Count;
};

template< class T, class DeleterT > class SharedPtrCountedImpl : public SharedPtrCountedBase {
public:
	SharedPtrCountedImpl( T* ptr, DeleterT deleter )
	: m_Ptr( ptr )
	, m_Deleter( deleter ) {
	}
	~SharedPtrCountedImpl() {
		m_Deleter( m_Ptr );
	}
	T* m_Ptr;
	DeleterT m_Deleter;
};

class SharedCount {
public:
	SharedCount() : m_Impl( 0 ) {
	}
	template< class T, class DeleterT >
	SharedCount( T* ptr, DeleterT del ) {
		m_Impl = ( ptr ) ? NEW SharedPtrCountedImpl< T, DeleterT >( ptr, del ) : 0;
	}
	~SharedCount();
	SharedCount( const SharedCount& );
	void operator=( const SharedCount& );

private:
	SharedPtrCountedBase* m_Impl;
};

} // namespace NTEngine

#endif // INCLUDED_NTENGINE_SHAREDPTRIMPL_H
// EOF